using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Media;

namespace Pongster
{
    public class SoundManager : GameComponent
    {
        public float MaxMusicVolume { get; set; }

        public float MaxSFXVolume { get; set; }

        protected Dictionary<string, SoundEffectInstance> Music = new Dictionary<string, SoundEffectInstance>();

        protected Dictionary<string, Song> Songs = new Dictionary<string, Song>();

        protected Dictionary<string, SoundEffectInstance> SFX = new Dictionary<string, SoundEffectInstance>();

        protected Dictionary<string, SoundEffect> SFXInstant = new Dictionary<string, SoundEffect>();
                
        protected List<SoundEffectInstance> master = new List<SoundEffectInstance>();

        protected ContentManager Content { get { return Game.Content; } }

        public SoundManager(Game game)
            : base(game)
        {
            MaxMusicVolume = 1f;
            MaxSFXVolume = 1f;

            Game.Components.Add(this);
            Game.Services.AddService(this.GetType(), this);
        }

        public override void Update(GameTime gameTime)
        {
            base.Update(gameTime);
        }

        public void LoadSFX(string name, string assetLocation)
        {
            SoundEffectInstance instance = Content.Load<SoundEffect>(assetLocation).CreateInstance();

            if (SFX.ContainsKey(name))
                SFX[name] = instance;
            else
                SFX.Add(name, instance);

            if (SFXInstant.ContainsKey(name))
                SFXInstant[name] = Content.Load<SoundEffect>(assetLocation);
            else
                SFXInstant.Add(name, Content.Load<SoundEffect>(assetLocation));

            if (!master.Contains(instance))
                master.Add(instance);

        }

        public void PlaySFX(string name, float volume = 1, float pan = 0, float pitch = 0, AudioListener[] listener = null, AudioEmitter emitter = null)
        {
            if (SFX.ContainsKey(name))
            {
                SFX[name].Volume = volume > MaxSFXVolume ? MaxMusicVolume : volume;
                SFX[name].Pan = pan;
                SFX[name].Pitch = pitch;

                if (listener != null && emitter != null)
                    SFX[name].Apply3D(listener, emitter);

                SFX[name].Play();
            }
        }

        public void PlayInstantSFX(string name, float volume = 1, float pan = 0, float pitch = 0)
        {
            if (SFXInstant.ContainsKey(name))
                SFXInstant[name].Play(volume > MaxSFXVolume ? MaxSFXVolume : volume, pitch, pan);
        }

        public void Apply3DToALLSFX(AudioListener[] listener, AudioEmitter emitter)
        {
            foreach (SoundEffectInstance sound in SFX.Values)
                sound.Apply3D(listener, emitter);
        }

        public void LoadSong(string title, string assetLocation)
        {
            Song instance = Content.Load<Song>(assetLocation);

            if (Songs.ContainsKey(title))
                Songs[title] = instance;
            else
                Songs.Add(title, instance);
        }

        public void PlaySong(string title, bool repeat)
        {
            if (Songs.ContainsKey(title))
            {
                try
                {
                    MediaPlayer.Play(Songs[title]);
                    MediaPlayer.IsRepeating = repeat;
                }
                catch { }
            }
        }

        public void StopSong()
        {
            MediaPlayer.Stop();
            MediaPlayer.IsRepeating = false;
        }

        public void PauseSong()
        {
            MediaPlayer.Pause();
        }

        public void ResumeSong()
        {
            MediaPlayer.Resume();
        }

        public void LoadMusic(string title, string assetLocation, bool loop = true, float volume = 1)
        {
            SoundEffectInstance instance = Content.Load<SoundEffect>(assetLocation).CreateInstance();
            instance.Volume = volume > MaxMusicVolume ? MaxMusicVolume : volume;
            instance.IsLooped = loop;

            if (Music.ContainsKey(title))
                Music[title] = instance;
            else
                Music.Add(title, instance);

            if (!master.Contains(instance))
                master.Add(instance);
        }

        public void PlayMusic(string title)
        {
            if (Music.ContainsKey(title))
            {
                switch (Music[title].State)
                {
                    case SoundState.Paused:
                        Music[title].Resume();
                        break;
                    case SoundState.Stopped:
                        Music[title].Play();
                        break;
                }
            }
        }

        public void PlayMusic(string title, float volume = 1)
        {
            if (Music.ContainsKey(title))
            {
                Music[title].Volume = volume > MaxMusicVolume ? MaxMusicVolume : volume;

                switch (Music[title].State)
                {
                    case SoundState.Paused:
                        Music[title].Resume();
                        break;
                    case SoundState.Stopped:
                        Music[title].Play();
                        break;
                }
            }
        }

        public void StopMusic(string title)
        {
            if (Music.ContainsKey(title))
            {
                switch (Music[title].State)
                {
                    case SoundState.Playing:
                        Music[title].Stop();
                        break;
                }
            }
        }

        public void PauseMusic(string title)
        {
            if (Music.ContainsKey(title))
            {
                switch (Music[title].State)
                {
                    case SoundState.Playing:
                        Music[title].Pause();
                        break;
                }
            }
        }


        public void StopAll()
        {
            List<SoundEffectInstance> playing = master.Where(sound => sound.State == SoundState.Playing).ToList();

            foreach (SoundEffectInstance sound in playing)
                sound.Stop();
        }

        public void PauseAll()
        {
            List<SoundEffectInstance> playing = master.Where(sound => sound.State == SoundState.Playing).ToList();

            foreach (SoundEffectInstance sound in playing)
                sound.Pause();
        }

        public void ResumeAll()
        {
            List<SoundEffectInstance> paused = master.Where(sound => sound.State == SoundState.Paused).ToList();

            foreach (SoundEffectInstance sound in paused)
                sound.Resume();
        }

    }
}
